from datetime import datetime, timedelta
import ezdxf
from ezdxf.math import Vec3
from ezdxf.addons import Importer
from ezdxf import bbox
from pathlib import Path
# SRC_FILE = r"E:\cadsecond-processing\drawingLibrary\嘉兴海宁全1.dxf"
# OUT_FOLDER = r"E:\cadsecond-processing\output"
# BLOCK_NAME = "model1_A3"
def delete_mtext_from_dxf(input_file, output_file):
    """
    删除多文字
    从指定的 DXF 文件中删除所有的 MTEXT 实体，并将结果保存到新的 DXF 文件中。

    参数:
    input_file (str): 输入的 DXF 文件路径。
    output_file (str): 输出的 DXF 文件路径。
    """
    try:
        # 1. 读入 DXF
        doc = ezdxf.readfile(input_file)
        msp = doc.modelspace()

        # 2. 收集要删除的 MTEXT
        texts_to_delete = [e for e in msp if e.dxftype() == "MTEXT"]

        # 3. 删除实体（不能在遍历过程中直接删除）
        for txt in texts_to_delete:
            msp.delete_entity(txt)

        # 4. 保存结果
        doc.saveas(output_file)
        print(f"已删除 {len(texts_to_delete)} 个 MTEXT 实体。")
        # return doc
    except Exception as e:
        print(f"处理文件时发生错误: {e}")

def purge_all_references(path_in: str, path_out: str):
    """
    删除：
      1. 所有外部参照块（XREF）的 INSERT
      2. 所有普通块参照（INSERT）
    不删除块定义本身，只删除引用。
    """
    doc = ezdxf.readfile(path_in)

    # 1. 遍历所有布局（模型空间 + 图纸空间）
    for layout in doc.layouts:
        # 找出所有块参照
        for insert in list(layout.query('INSERT')):  # list 防止迭代时修改
            insert.destroy()

    doc.saveas(path_out)
    print(f'已删除所有块参照，结果保存至 {path_out}')
    return doc


# delete_mtext_from_dxf("嘉兴海宁全1.dxf","jiaxing_mtext.dxf")
# purge_all_references("jiaxing_mtext.dxf","jiaxing_no_refs.dxf")

def process_inserts(input_file, block_name="model1_A3"):
    """
    处理指定 DXF 文件中的 INSERT 实体，并打印相关信息。

    参数:
    input_file (str): 输入的 DXF 文件路径。
    block_name (str): 要处理的块名称。
    """
    try:
        # 读入 DXF
        doc = ezdxf.readfile(input_file)
        msp = doc.modelspace()

        # 获取块定义
        block = doc.blocks.get(block_name)
        if block is None:
            raise ValueError(f"找不到块定义 {block_name}")

        # 收集块定义中的 ATTDEF
        attdefs = {att.dxf.tag: att for att in block.query("ATTDEF")}
        drawing_block_name_position = []
        # 遍历 INSERT 实体
        for insert in msp.query(f'INSERT[name=="{block_name}"]'):
            print(f"\nINSERT handle={insert.dxf.handle} 插入点={insert.dxf.insert}")

            # 处理 INSERT 里已有的 ATTRIB
            for attrib in insert.attribs:
                if attrib.dxf.tag == 'DWGTYPE':
                    print(f"  ATTRIB tag='{attrib.dxf.tag}' "
                          f"值='{attrib.dxf.text}' 位置={attrib.dxf.insert}")
                    drawing_block_name_position.append({attrib.dxf.text:tuple(attrib.dxf.insert)})
            # 处理块定义中未被覆盖的 ATTDEF
            found_tags = {a.dxf.tag for a in insert.attribs}
            for tag, attdef in attdefs.items():
                if tag not in found_tags:
                    pt = insert.dxf.insert + attdef.dxf.insert.rotate(insert.dxf.rotation)
                    print(f"  块定义 tag='{tag}' 默认值='{attdef.dxf.text}' 位置={pt}")
                    drawing_block_name_position.append({tag: tuple(attdef.dxf.insert)})
        return drawing_block_name_position
    except Exception as e:
        print(f"处理文件时发生错误: {e}")

def _entity_inside(entity, box):
    """判断实体的包围盒是否完全落在 box 内"""
    try:
        ebox = bbox.extents([entity])
    except Exception:
        return False
    return box.inside(ebox.extmin) and box.inside(ebox.extmax)


def start_fentu(OUT_FOLDER,SRC_FILE,BLOCK_NAME="model1_A3"):
    now = datetime.now()
    delete_old_files(OUT_FOLDER, cutoff_time=now - timedelta(minutes=5))
    src_doc = ezdxf.readfile(SRC_FILE)
    src_msp = src_doc.modelspace()

    block_refs = list(src_msp.query(f'INSERT[name=="{BLOCK_NAME}"]'))
    if not block_refs:
        print(f"未找到名为 {BLOCK_NAME} 的块参照")
        return
    sub_graph_path_list = []
    sub_graph_info = process_inserts(SRC_FILE)
    print(f'Here is the sub_graph:{sub_graph_info}')
    for idx, ref in enumerate(block_refs, 1):
        # 计算块参照的包围盒
        try:
            ref_box = bbox.extents([ref])
        except Exception:
            print(f"无法计算第 {idx} 个 {BLOCK_NAME} 的包围盒，跳过")
            continue

        # 找出落在 box 内的实体
        entities_to_copy = [
            e for e in src_msp
            if _entity_inside(e, ref_box)
        ]
        if not entities_to_copy:          # 空文件，直接跳过
            print(f"第 {idx} 个 {BLOCK_NAME} 范围内无实体，跳过")
            continue

        # 新建文档
        new_doc = ezdxf.new(dxfversion=src_doc.dxfversion)
        new_msp = new_doc.modelspace()

        importer = Importer(src_doc, new_doc)
        importer.import_entities(entities_to_copy)
        importer.finalize()
        # 关键：用 Importer 复制所有依赖（图层、线型、块定义等）
        # importer = ezdxf.Importer(src_doc, new_doc)
        # importer.import_entities(entities_to_copy)
        # importer.finalize()              # 必须调用
        now_str = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
        graph_name = next(iter(sub_graph_info[idx-1]))
        out_path = Path(OUT_FOLDER) / f"{graph_name}_{idx}_{now_str}.dxf"
        new_doc.saveas(out_path)
        print(f"已生成：{out_path}")
        sub_graph_path_list.append(out_path)
    return sub_graph_path_list
# print(process_inserts("E:\python\MCP_s\cadsecond-processing\drawingLibrary\嘉兴海宁全1.dxf"))

def delete_old_files(folder, cutoff_time):
    """删除 folder 中早于 cutoff_time 的 .dxf 文件"""
    for file in Path(folder).glob("*.dxf"):
        try:
            mtime = datetime.fromtimestamp(file.stat().st_mtime)
            if mtime < cutoff_time:
                file.unlink()
                print(f"已删除旧文件：{file}")
        except Exception as e:
            print(f"删除文件失败：{file}, 错误：{e}")


def within_radius(p1: Vec3, p2: Vec3, dist: float) -> bool:
    return p1.distance(p2) <= dist


def tiankui_parsing(input_file_path, SEARCH_RADIUS=2000, BLOCK_NAME="平台"):
    """
    input_file_path: 输入的 DXF 文件路径
    SEARCH_RADIUS: 搜索半径（单位：图纸单位）
    BLOCK_NAME: 要检测的块名
    """
    # 1. 打开图纸
    doc = ezdxf.readfile(input_file_path)
    msp = doc.modelspace()

    TARGET_BLOCK_NAME = BLOCK_NAME  # 要检测的块名
    SEARCH_RADIUS = SEARCH_RADIUS  # 搜索半径（单位：图纸单位）

    # 2. 取出全部块参照和 HATCH
    all_blocks = list(msp.query('INSERT'))
    outcome_list = []
    # 4. 遍历每个目标块
    for blk in all_blocks:
        if TARGET_BLOCK_NAME.upper() not in blk.dxf.name.upper():
            continue

        center = blk.dxf.insert

        # ------- 块参照 -------
        print(f'\n中心块 "{blk.dxf.name}" @ {center}')
        print('邻近的块参照：')
        blocks_near = 0
        block_name_list = []
        for b in all_blocks:
            if b is blk:  # 跳过自己
                continue
            if within_radius(center, b.dxf.insert, SEARCH_RADIUS):
                blocks_near += 1
                print(f'  {blocks_near}. 名称: {b.dxf.name}  位置: {b.dxf.insert}')
                block_name_list.append(b.dxf.name)
        print(f'合计块参照数量：{blocks_near}')
        outcome_list.append({blk.dxf.name:block_name_list})
    return outcome_list



if __name__ == "__main__":
    print(tiankui_parsing("E:\python\MCP_s\cadsecond-processing\output\远端基站天馈安装示意图_7_20250718_110318_994.dxf"))
    # start_fentu("output","drawingLibrary/宁波鄞州.dxf", "model1_A3")
    # 使用示例 - 替换为你的DXF文件路径
    # print(f'Here is name of graph:{process_inserts("./drawingLibrary/嘉兴海宁全1.dxf")}')
